package com.senriot.quickup.service

import com.alibaba.fastjson.JSON
import com.egzosn.pay.ali.api.AliPayService
import com.egzosn.pay.ali.bean.AliPayMessage
import com.egzosn.pay.ali.bean.AliTransactionType
import com.egzosn.pay.common.api.PayMessageHandler
import com.egzosn.pay.common.bean.MethodType
import com.egzosn.pay.common.bean.PayMessage
import com.egzosn.pay.common.bean.PayOrder
import com.egzosn.pay.common.bean.TransferOrder
import com.egzosn.pay.common.http.HttpConfigStorage
import com.egzosn.pay.wx.api.WxPayService
import com.egzosn.pay.wx.bean.WxPayMessage
import com.egzosn.pay.wx.bean.WxTransactionType
import com.egzosn.pay.wx.bean.WxTransferType
import com.fasterxml.jackson.databind.ObjectMapper
import com.senriot.cloud.aliyun.DeviceManager
import com.senriot.cloud.aliyun.ThingModelManager
import com.senriot.cloud.common.result.R
import com.senriot.cloud.common.result.fail
import com.senriot.cloud.common.result.success
import com.senriot.quickup.domain.Device
import com.senriot.quickup.domain.Order
import com.senriot.quickup.domain.OrderBonus
import com.senriot.quickup.domain.QDevice
import com.senriot.quickup.domain.enums.OrderType
import com.senriot.quickup.repository.DeviceRepository
import com.senriot.quickup.repository.OrderRepository
import com.senriot.quickup.repository.UserRepository
import com.senriot.quickup.security.UserNotActivatedException
import com.senriot.quickup.security.getCurrentUserLogin
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.math.BigDecimal
import java.text.SimpleDateFormat
import java.util.*
import javax.annotation.PostConstruct
import javax.transaction.Transactional


@Service
@Transactional
class PayService(
        val aliPayService: AliPayService,
        val wxPayService: WxPayService,
        private val deviceRepository: DeviceRepository,
        private val orderRepository: OrderRepository,
        private val deviceManager: DeviceManager,
        private val thingModelManager: ThingModelManager,
        private val userRepository: UserRepository,
        private val om: ObjectMapper
)
{
    private val log = LoggerFactory.getLogger(this.javaClass)

    @PostConstruct
    fun init()
    {
        aliPayService.payMessageHandler = aliPayMessageHandler
        wxPayService.payMessageHandler = wxPayMessageHandler
//
//        //请求连接池配置
//        val  httpConfigStorage =  HttpConfigStorage();
//        //最大连接数
//        httpConfigStorage.maxTotal = 20;
//        //默认的每个路由的最大连接数
//        httpConfigStorage.defaultMaxPerRoute = 10;
      //  service =  new AliPayService(aliPayConfigStorage, httpConfigStorage);
        //增加支付回调消息拦截器
        //service.addPayMessageInterceptor(new AliPayMessageInterceptor());

    }

    private val sdf = SimpleDateFormat("yyyyMMddHHmmssSSS")

    fun genOrderNo(): String
    {
        return "R" + sdf.format(Date()) + (1 + (Math.random() * 10000).toInt()) + 530L
    }

    private fun genOrder(device: Device, orderType: OrderType): Order
    {
        val order = Order(
                orderType = orderType,
                ordersId = genOrderNo(),
                device = device,
                amount = device.price,
                status = 0,
                isCashOut = false,
                province = device.province,
                city = device.city,
                district = device.district,
                address = device.address,
                store = device.store
        )
        device.bonuses.forEach {
            order.addBonus(OrderBonus(user = it.user, amount = it.amount))
        }
        return orderRepository.saveAndFlush(order)
    }

    fun createOrder(deviceId: String, type: OrderType): String?
    {
        return deviceRepository.findOne(QDevice.device.deviceId.eq(deviceId)).map {
            if (it.stock > 0)
            {
                val order = genOrder(it, type)
                val payOrder = PayOrder("快醒自助购物", "kuaixing.vip", it.price, order.ordersId)
                if (type == OrderType.weixin)
                {
                    payOrder.transactionType = WxTransactionType.NATIVE
                    wxPayService.getQrPay(payOrder)
                } else
                {
                    log.debug("payConfigStorage ${om.writeValueAsString(aliPayService.payConfigStorage)}")
                    payOrder.transactionType = AliTransactionType.SWEEPPAY
                    aliPayService.getQrPay(payOrder)
                }
            } else
            {
                throw RuntimeException("库存不足")
            }
        }.orElseThrow { RuntimeException("设备ID无效") }
    }

    val aliPayMessageHandler = PayMessageHandler<AliPayMessage, AliPayService> { payMessage, _, payService ->
        log.debug("支付宝支付消息  $payMessage")
        //交易状态
        val tradeStatus = payMessage.tradeStatus

        //订单号
//        orderService.load(payMessage.outTradeNo).map {
//            it.amount = payMessage.totalAmount
//
//        }
//        payMessage.outTradeNo

        log.debug(payMessage.toString())
        //上下文对象中获取账单
//        AmtApply amtApply = (AmtApply)context.get("amtApply");
        //日志存储
//        amtPaylogService.createAmtPaylogByCallBack(amtApply,  message.toString());
        //交易完成
        if ("TRADE_SUCCESS" == tradeStatus || "TRADE_FINISHED" == tradeStatus)
        {
            deliverCommodity(payMessage)
            payService.getPayOutMessage("success", "成功")

        }/* else if ("WAIT_BUYER_PAY".equals(trade_status) || "TRADE_CLOSED".equals(trade_status)) {

        }*/
        else
            payService.getPayOutMessage("fail", "失败")

    }


    /**
     * 公众号支付
     * @param deviceId String
     * @param openId String
     */
    fun jsApi(deviceId: String, openId: String): R<MutableMap<String, Any>>
    {
        return deviceRepository.findOne(QDevice.device.deviceId.eq(deviceId)).map {
            if (it.stock > 0)
            {
                val order = genOrder(it, OrderType.weixin)
                val payOrder = PayOrder("快醒自助购物", "kuaixing.vip", it.price, order.ordersId)
                payOrder.transactionType = WxTransactionType.JSAPI
                payOrder.openid = openId
                success(wxPayService.orderInfo(payOrder).apply { put("code", 0) })
            } else
            {
                fail("库存不足")
            }

        }.orElse(fail("设备ID无效"))
    }


    fun h5Pay(deviceId: String): R<MutableMap<String, Any>>
    {
        return deviceRepository.findOne(QDevice.device.deviceId.eq(deviceId)).map {
            if (it.stock > 1)
            {
                val order = genOrder(it, OrderType.weixin)
                val payOrder = PayOrder("快醒自助购物", "kuaixing.vip", it.price, order.ordersId)
                payOrder.transactionType = WxTransactionType.MWEB
                success(wxPayService.orderInfo(payOrder).apply { put("code", 0) })
            } else
            {
                fail("库存不足")
            }

        }.orElse(fail("设备ID无效"))
    }

    fun toWapPay(deviceId: String): R<String>
    {
        return deviceRepository.findOne(QDevice.device.deviceId.eq(deviceId)).map {
            if (it.stock > 0)
            {
                val order = genOrder(it, OrderType.alipay)
                val payOrder = PayOrder("快醒自助购物", "kuaixing.vip", it.price, order.ordersId)
                payOrder.transactionType = AliTransactionType.WAP
                val orderInfo = aliPayService.orderInfo(payOrder).apply { put("code", 0) }
                success(aliPayService.buildRequest(orderInfo, MethodType.POST))
            } else
            {
                fail("库存不足")
            }
        }.orElse(fail("设备ID无效"))
    }


    /**
     * 出货
     * @param payMessage PayMessage
     */
    private fun deliverCommodity(payMessage: PayMessage)
    {
        orderRepository.findByOrdersId(payMessage.outTradeNo).map {
            it.status = 1
            if (payMessage is WxPayMessage)
                it.paymentSystemOrderId = payMessage.transactionId
            if (payMessage is AliPayMessage)
                it.paymentSystemOrderId = payMessage.tradeNo
            orderRepository.saveAndFlush(it)
            /**
             * 出货
             */
            val param = hashMapOf<String, Any>()
            param["x"] = 0
            param["y"] = 0
            param["quantity"] = 1
            param["orderNo"] = payMessage.outTradeNo
            thingModelManager.invokeThingService(
                    DeviceName = it.device?.deviceId,
                    ProductKey = it.device?.productKey,
                    Identifier = "deliverCommodity",
                    Args = JSON.toJSONString(param)
            )
        }
    }

    /**
     * 获取单价
     * @param deviceId String 设备ID
     * @return BigDecimal
     */
    fun loadPrice(deviceId: String): R<BigDecimal>
    {
        return deviceRepository.findByDeviceId(deviceId).map {
            success(it.price!!)
        }.orElseGet { fail("设备不存在") }
    }

    /**
     * 获取支付数据
     * @param deviceId String
     * @param refId String
     * @param remoteAddr String?
     * @param openId String
     * @return Any?
     */
    fun payment(
            deviceId: String,
            refId: String,
            remoteAddr: String?,
            openId: String
    ): R<*>
    {
        return if (openId == "alipay") toWapPay(deviceId) else jsApi(deviceId, openId)
    }

    fun transfer(openId: String, amount: BigDecimal): MutableMap<String, Any>?
    {
        return getCurrentUserLogin().map { login ->
            userRepository.findOneByLogin(login).map {
                val order = Order(
                        orderType = OrderType.weixin,
                        ordersId = genOrderNo(),
                        amount = amount,
                        status = 0,
                        isCashOut = true,
                        user = it
                )
                val transferOrder = TransferOrder().apply {
                    outNo = genOrderNo()
                    payeeAccount = it.openId
                    remark = "快醒提现"
                    setAmount(order.amount)
                    transferType = WxTransferType.TRANSFERS
                }

                val result = wxPayService.transfer(transferOrder)
                if (result["result_code"] == "SUCCESS")
                {
                    order.status = 1
                    order.paymentSystemOrderId = result["payment_no"] as String?
                } else
                {
                    order.remark = result["err_code_des"] as String?
                }
                orderRepository.saveAndFlush(order)
                result
            }.orElseThrow {
                UserNotActivatedException("用户不存在")
            }
        }.orElseThrow { UserNotActivatedException("用户不存在") }
    }

    val wxPayMessageHandler =
            PayMessageHandler { wxPayMessage: WxPayMessage, _: MutableMap<String, Any>, wxPayService: WxPayService ->
                log.info("微信支付消息  ${om.writeValueAsString(wxPayMessage)}")
                if ("SUCCESS" == wxPayMessage.payMessage["result_code"])
                {
                    if (wxPayMessage.tradeType == "JSAPI")
                    {
                        deliverCommodity(wxPayMessage)
                    }

                    wxPayService.getPayOutMessage("SUCCESS", "OK")
                } else
                    wxPayService.getPayOutMessage("FAIL", "失败")
            }
}
